#pragma once
#include "Log.hpp"
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <fstream>

const string Sep = "\r\n";
const string Blank_line = Sep;
const string LineSep = " ";
const string HeadLineSep = ": ";
const string default_home_page = "wwwroot";
const string HttpVersion = "HTTP/1.0";
const string page404 = "wwwroot/404.html";
const string firstPage = "index.html";

class HttpRequest
{
public:
    HttpRequest()
    {
    }
    ~HttpRequest()
    {
    }

    bool HasArgs()
    {
        return _isexec;
    }

    void Deserialize(string &req)
    {
        if (ParseOneReqLine(req, &_req_line, Sep)) // 解析请求行
        {
            DetailedParseReqLine(_req_line); // 详细解析"请求行"中的每一个,存入对象Protocol中
            ParseReqHead(req);               // 解析请求报头行
            _body = req;                     // 剩下的就是内容

            if (_method == "GET")
            {
                //  /login?username=zhang&password=123456
                auto pos = _uri.find("?");
                if (pos != string::npos)
                {
                    _isexec = true;
                    _path = _uri.substr(0, pos);
                    _args = _uri.substr(pos + 1);
                }
            }
            else if (_method == "POST")
            {
                auto pos = _uri.rfind("/");
                if (pos != string::npos)
                {
                    _isexec = true;
                    _path = _uri.substr(pos);
                    _args = _body;
                }
            }
        }
    }

    // 解析一行请求
    bool ParseOneReqLine(string &req, string *out, const string &sep)
    {
        auto pos = req.find(sep);
        if (pos == string::npos)
            return false;
        *out = req.substr(0, pos);
        req.erase(0, pos + sep.size());
        return true;
    }

    // 解析请求报头行
    bool ParseReqHead(string &req)
    {
        string line;
        while (true)
        {
            bool ret = ParseOneReqLine(req, &line, Sep);
            if (ret && !line.empty())
            {
                _req_head.push_back(line);
                // 读到报头
            }
            else if (ret && line.empty())
            {
                // 读到空行
                _blank_line = Blank_line;
                break;
            }
            else
            {
                return false;
            }
        }
        ParseReqHeadKV(); // 详细解析
        return true;
    }

    // 详细解析每一行请求报头行,构建kv
    void ParseReqHeadKV()
    {
        string key, value;
        for (string &line : _req_head)
        {
            if (SplitLine(line, HeadLineSep, &key, &value))
            {
                _req_head_kv[key] = value;
            }
        }
    }

    void Print()
    {
        cout << "method:" << _method << endl;
        cout << "uri:" << _uri << endl;
        cout << "version:" << _version << endl;
        for (auto &[key, value] : _req_head_kv)
        {
            cout << key << " # " << value << endl;
        }

        cout << _blank_line << endl;
        cout << _body << endl;
    }

    // 根据请求中的uri，获取服务器中的资源
    string GetContent(string path)
    {
        // 2.采用二进制读取
        string content;
        ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return string();

        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);

        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        LOG(LogGrade::NORMAL) << "content length:" << content.size();
        return content;

        // 1.采用文本读，图片类的会出问题
        //  string content;
        //  ifstream in(_uri);
        //  if(!in.is_open())
        //      return string();
        //  string line;
        //  while(getline(in,line))
        //  {
        //      content += line;
        //  }
        //  in.close();
        //  return content;
    }

    string Geturi()
    {
        return _uri;
    }

    void Seturi(string uri)
    {
        _uri = uri;
    }

    string getPath()
    {
        return _path;
    }

    string getArgs()
    {
        return _args;
    }

private:
    // 详细解析请求行中的每一个
    bool DetailedParseReqLine(string &reqline)
    {
        stringstream ss(reqline);
        ss >> _method >> _uri >> _version;
        return true;
    }

    bool SplitLine(string &req, const string &sep, string *key, string *value)
    {
        auto pos = req.find(sep);
        if (pos == string::npos)
            return false;
        *key = req.substr(0, pos);
        *value = req.substr(pos + sep.size());
        return true;
    }

private:
    string _req_line;         // 请求行
    vector<string> _req_head; // 请求报头
    string _blank_line;       // 空行
    string _body;             // 内容
    string _path;             // 请求的“资源”  /login
    string _args;             // 请求所携带的参数
    bool _isexec = false;

    // 将请求行、报头进行更进一步的解析
    string _method;                             // 请求方法
    string _uri;                                // 用户请求的就是这个
    string _version;                            // 协议版本
    unordered_map<string, string> _req_head_kv; // 请求报头K:V式
};

class HttpResponse
{
public:
    HttpResponse()
        : _version(HttpVersion)
    {
    }

    ~HttpResponse()
    {
    }

    void Build(HttpRequest &req)
    {
 #define TestRedir
#ifdef TestRedir
        // 测试重定向与状态码3XX
        _status_code = 302;
        _scode_desc = getDescByscode(_status_code);
        SetHeadKV("Location", "http://120.46.174.204:8080/register.html");
        // 将kv式的响应报头转换为string型
        for (auto &[key, value] : _head_kv)
        {
            _resp_head.push_back(key + HeadLineSep + value + Sep);
        }
#else
        string uri = default_home_page + req.Geturi();
        // wwwroot/
        if (uri.back() == '/')
        {
            // wwwroot/index.html
            uri += firstPage;
            req.Seturi(uri); // 为了默认打开首页
        }

        _content = req.GetContent(uri); // 获取uri中的内容

        if (_content.empty())
        {
            // 请求资源不存在，设置状态码
            _status_code = 404;
            req.Seturi(page404);
            _content = req.GetContent(uri);
        }
        else
        {
            _status_code = 200;
        }
        _scode_desc = getDescByscode(_status_code);

        // 构建响应报头
        // 1.长度响应报头(可能未空)
        if (!_content.empty())
        {
            SetHeadKV("Content-length", to_string(_content.size()));
        }
        // 2. 类型响应报头（不为空）
        string resp_suffix = GetTypeBySuffix(uri);
        string resp_type = Suffix2Desc(resp_suffix);

        SetHeadKV("Content-type", resp_type);
#endif
    }

    string GetTypeBySuffix(string &uri)
    {
        auto pos = uri.rfind('.');
        if (pos == string::npos)
            return string();
        else
            return uri.substr(pos); // 取后缀
    }

    // 后缀转类型描述
    string Suffix2Desc(string &resp_suffix)
    {
        if (".html" == resp_suffix)
            return "text/html";
        else if (".jpg" == resp_suffix)
            return "application/x-jpg";
        return "text/html";
    }

    // 通过状态码获取状态描述
    string getDescByscode(int status_code)
    {

        switch (status_code)
        {
        case 404:
            return "Not Found";
        case 200:
            return "OK";
        case 301:
            return "Moved Permanently";
        case 302:
            return "See Other";
        }
        return "";
    }
    int GetStatusCode()
    {
        return _status_code;
    }

    void SetStatusCode(int code)
    {
        _status_code = code;
    }

    void SetStatusDesc(int code)
    {
        _scode_desc = getDescByscode(code);
    }

    // 添加响应报头
    void SetHeadKV(const string &key, const string &value)
    {
        _head_kv[key] = value;
    }

    void SetContent(string& content)
    {
        _content = content;
    }

    // 序列化
    void Serialize(string *resp)
    {
        // 将kv式的响应报头转换为string型
        for (auto &[key, value] : _head_kv)
        {
            _resp_head.push_back(key + HeadLineSep + value + Sep);
        }
        _resp_line = _version + LineSep + to_string(_status_code) + LineSep + _scode_desc + Sep; // 响应行
        _blank_line = Sep;                                                                       // 空行
        _body = _content;                                                                        // 内容

        *resp = _resp_line;
        for (auto &line : _resp_head)
        {
            *resp += line; // 响应报头
        }
        *resp += _blank_line;
        *resp += _body;
    }

private:
    string _version;                        // 协议版本
    int _status_code;                       // 状态码
    string _scode_desc;                     // 响应描述
    unordered_map<string, string> _head_kv; // 响应报头K:V式
    string _content;                        // 给用户要返回的资源

    // 最终要这四部分
    string _resp_line;         // 响应行
    vector<string> _resp_head; // 响应报头
    string _blank_line;        // 空行
    string _body;              // 内容
};
